#ifndef _GlsxCommon_Thread_H_
#define _GlsxCommon_Thread_H_

#include "GlsxCommon.h"
#include "Core/Noncopyable.h"

BEGIN_GLSX_NAMESPACE

//#define _TTHREAD_DISABLE_ASSIGNMENT(name) \
//	name(const name&); \
//	name& operator=(const name&);

	class GlsxCommon_API Mutex 
	{
	public:
		Mutex(): mAlreadyLocked(false)
		{
			InitializeCriticalSection(&mHandle);
		}

		~Mutex()
		{
			DeleteCriticalSection(&mHandle);
		}

		inline void lock()
		{
			EnterCriticalSection(&mHandle);
			while(mAlreadyLocked) Sleep(1000); // Simulate deadlock...
			mAlreadyLocked = true;
		}

		inline bool tryLock()
		{
			bool ret = (TryEnterCriticalSection(&mHandle) ? true : false);
			if(ret && mAlreadyLocked)
			{
				LeaveCriticalSection(&mHandle);
				ret = false;
			}
			return ret;
		}

		inline void unlock()
		{
			mAlreadyLocked = false;
			LeaveCriticalSection(&mHandle);
		}

	private:

		CRITICAL_SECTION mHandle;
		bool mAlreadyLocked;
		friend class ConditionVariable;
	};

	class GlsxCommon_API RecursiveMutex : public NonCopyable
	{
	public:
		RecursiveMutex()
		{
			InitializeCriticalSection(&mHandle);
		}

		~RecursiveMutex()
		{
			DeleteCriticalSection(&mHandle);
		}

		inline void lock()
		{
			EnterCriticalSection(&mHandle);
		}

		inline bool tryLock()
		{
			return TryEnterCriticalSection(&mHandle) ? true : false;
		}

		inline void unlock()
		{
			LeaveCriticalSection(&mHandle);
		}

		//_TTHREAD_DISABLE_ASSIGNMENT(RecursiveMutex)

	private:

		CRITICAL_SECTION mHandle;
		friend class ConditionVariable;
	};
	
	template <class T> class LockGuard 
	{
	public:
		typedef T mutex_type;

		LockGuard() : mMutex(0) {}

		explicit LockGuard(mutex_type &aMutex)
		{
			mMutex = &aMutex;
			mMutex->lock();
		}

		~LockGuard()
		{
			if(mMutex) mMutex->unlock();	
		}

	private:
		mutex_type * mMutex;
	};

	class GlsxCommon_API ConditionVariable : public NonCopyable
	{
	public:
		ConditionVariable();

		~ConditionVariable();

		template <class _mutexT>
		inline void wait(_mutexT &aMutex)
		{
			EnterCriticalSection(&mWaitersCountLock);
			++ mWaitersCount;
			LeaveCriticalSection(&mWaitersCountLock);
			aMutex.unlock();
			_wait();
			aMutex.lock();
		}

		void notifyOne();
		void notifyAll();

		//_TTHREAD_DISABLE_ASSIGNMENT(ConditionVariable)

	private:
		void _wait();
		HANDLE mEvents[2];                  ///< Signal and broadcast event HANDLEs.
		unsigned int mWaitersCount;         ///< Count of the number of waiters.
		CRITICAL_SECTION mWaitersCountLock; ///< Serialize access to mWaitersCount.
	};

	class GlsxCommon_API Thread : public NonCopyable
	{
	public:
		Thread() : mHandle(0), mNotAThread(true), mWin32ThreadID(0){}

		Thread(void (*aFunction)(void *), void * aArg);

		~Thread();

		void join();
		bool joinable() const;
		void detach();
		void yield();
		void sleep(unsigned int ms);

		DWORD getId() const;

		inline HANDLE getNativeHandle() { return mHandle; }

		//_TTHREAD_DISABLE_ASSIGNMENT(Thread)

	protected:
		static DWORD WINAPI wrapperFunction(LPVOID * aArg);

	private:
		HANDLE mHandle;   
		mutable Mutex mDataMutex;
		bool mNotAThread;        
		DWORD mWin32ThreadID;
	};

	// Define/macro cleanup
//#undef _TTHREAD_DISABLE_ASSIGNMENT

END_GLSX_NAMESPACE

#endif